package model.code.line;

import lang.asm.ASMEncode;
import observer.Copiable;

/**
 * This represents the value of a constant expression possibly containing an abolute relocation and a difference relocation.
 * @author Neil Dickson
 */
public class Immediate implements Copiable<Immediate> {
	/**
	 * True if this immediate stores a floating-point number, else false and stores an integer.
	 */
	public	boolean	isDouble;
	/**
	 * This is the sum of the non-relocation constants (0 if none).
	 */
	public	long constant;
	/**
	 * This allows for an absolute relocation, e.g. "offset MyVariable".
	 */
	public	ASMEncode.Relocation	relocation;
	/**
	 * This allows for a difference relocation, e.g. "offset EndOfVariables - offset StartOfVariables".
	 */
	public	ASMEncode.Relocation	diffRelocation;

	public boolean isZero() {
		return constant==0 && relocation==null && diffRelocation==null;
	}

	public boolean isOne() {
		return !isDouble && constant==1 && relocation==null && diffRelocation==null;
	}

	public Immediate(long constant) {
		this(constant,null,null);
	}
	public Immediate(long constant,boolean isDouble) {
		this(constant,null,null,isDouble);
	}
	public Immediate(long constant, ASMEncode.Relocation relocation) {
		this(constant,relocation,null);
	}
	public Immediate(long constant, ASMEncode.Relocation relocation, ASMEncode.Relocation diffRelocation) {
		this(constant,relocation,diffRelocation,false);
	}
	public Immediate(long constant, ASMEncode.Relocation relocation, ASMEncode.Relocation diffRelocation,boolean isDouble) {
		this.constant = constant;
		this.relocation = relocation;
		this.diffRelocation = diffRelocation;
		this.isDouble = isDouble;
	}

	public boolean equals(Object o) {
		if (!(o instanceof Immediate)) {
			return false;
		}
		Immediate that = (Immediate)o;
		if (isDouble!=that.isDouble || constant!=that.constant) {
			return false;
		}
		if ((relocation==null && that.relocation!=null) || (relocation!=null && that.relocation==null)) {
			return false;
		}
		return (relocation==null || relocation.equals(that.relocation)) && (diffRelocation==null || diffRelocation.equals(that.diffRelocation));
	}

	public String toString() {
		return (isDouble?Double.toString(Double.longBitsToDouble(constant)):Long.toString(constant))+((relocation!=null)?"+relocation":"")+((diffRelocation!=null)?"+difference of relocations":"");
	}

	public Immediate copy() {
		return new Immediate(constant,(relocation==null) ? null : relocation.copy(),(diffRelocation==null) ? null : diffRelocation.copy(),isDouble);
	}
}
